﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UIElements;
using DataModel;
using System.Windows.Input;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Collections.ObjectModel;
using UIElements.Service;
using EnvDTE;
using EnvDTE80;
using EnvDTE100;

namespace UIElements.ViewModel
{
    public class MainControlViewModel : ViewModelBase
    {
        #region Private Fields

        private MainControl mainControl;
        private EnvDTE.DTE dte;

        #endregion

        #region Constructors

        public MainControlViewModel()
            : base()
        {
            // renew the view model
            RefreshPatternTemplates();
            RefreshPatternLocations();
        }

        public MainControlViewModel(MainControl mainControl)
            : this()
        {
            // set the main control
            this.mainControl = mainControl;
        }

        public MainControlViewModel(MainControl mainControl, DTE dte)
            : base()
        {
            this.dte = dte;
            this.mainControl = mainControl;
            //RefreshPatternTemplates(dte);
            RefreshPatternTemplates();
        }

        #endregion

        #region Properties

        private TreeViewItemViewModel editableTreeViewItem;
        public TreeViewItemViewModel EditableTreeViewItem
        {
            get { return editableTreeViewItem; }
            set
            {
                editableTreeViewItem = value;
                OnPropertyChanged("EditableTreeViewItem");
            }
        }

        private ObservableCollection<TreeViewItemViewModel> patternTemplates;
        public ObservableCollection<TreeViewItemViewModel> PatternTemplates
        {
            get { return patternTemplates; }
            set
            {
                patternTemplates = value;
                OnPropertyChanged("PatternTemplates");
            }
        }

        private ObservableCollection<PatternLocationViewModel> patternLocations;
        public ObservableCollection<PatternLocationViewModel> PatternLocations
        {
            get { return patternLocations; }
            set
            {
                patternLocations = value;
                OnPropertyChanged("PatternLocations");
            }
        }

        #endregion

        #region Event Handlers

        public void tvPatternExplorer_OnMouseRightButtonUp(object sender, MouseButtonEventArgs e)
        {
            try
            {
                TreeViewItem selectedItem = VisualUpwardSearch<TreeViewItem>(e.OriginalSource as DependencyObject) as TreeViewItem;
                TreeViewItem selectedItemParent = GetParentTreeViewItem(selectedItem as DependencyObject);
            }
            catch (Exception ex)
            {
                VSService.WriteToOutputWindow(dte, "\nError: " + ex.Message);
            }
        }

        internal void tvPatternExplorer_OnPreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            try
            {
                TreeViewItem item = VisualUpwardSearch<TreeViewItem>(e.OriginalSource as DependencyObject) as TreeViewItem;

                if (item != null)
                {
                    item.IsSelected = true;
                    item.Focus();
                    e.Handled = true;
                }
            }
            catch (Exception ex)
            {
                VSService.WriteToOutputWindow(dte, "\nError: " + ex.Message);
            }
        }

        internal void tvPatternExplorer_OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            try
            {
                // get the selected item
                TreeViewItem selectedItem = VisualUpwardSearch<TreeViewItem>(e.OriginalSource as DependencyObject) as TreeViewItem;

                // check if selected item is null
                if (selectedItem == null)
                {
                    // clear selection on the tree view if necessary
                    if (mainControl.tvPatternExplorer.SelectedItem != null && mainControl.tvPatternExplorer.SelectedItem is TreeViewItemViewModel)
                    {
                        (mainControl.tvPatternExplorer.SelectedItem as TreeViewItemViewModel).IsSelected = false;
                    }

                    // display no properties when no item is selected
                    //mainControl.dgPatternProperties.DataContext = null;

                    // hide the pattern description if no item is selected
                    //mainControl.tbxPatternDescription.Visibility = Visibility.Hidden;
                    mainControl.spPatternDescription.Visibility = Visibility.Hidden;
                }
                else
                {
                    // guarantee the selection of the item
                    selectedItem.IsSelected = true;

                    // set the data context to display corresponding properties (either pattern model/instance)
                    //mainControl.dgPatternProperties.DataContext = (selectedItem.Header as TreeViewItemViewModel).GetProperties();

                    // set the pattern description to display corresponding description
                    if (selectedItem.Header != null && selectedItem.Header is PatternTemplateViewModel)
                    {
                        mainControl.spPatternDescription.Visibility = Visibility.Visible;
                        var selectedPatternTemplate = selectedItem.Header as PatternTemplateViewModel;
                        if (string.IsNullOrEmpty(selectedPatternTemplate.TemplateComments))
                        {
                            mainControl.tbxPatternDescription.Text = string.Empty;
                        }
                        else
                        {
                            mainControl.tbxPatternDescription.Text = selectedPatternTemplate.TemplateComments;
                        }
                    }
                    else if (selectedItem.Header != null && selectedItem.Header is PatternInstanceViewModel)
                    {
                        mainControl.spPatternDescription.Visibility = Visibility.Visible;
                        var selectedPatternInstance = selectedItem.Header as PatternInstanceViewModel;
                        if (string.IsNullOrEmpty(selectedPatternInstance.InstanceComments))
                        {
                            mainControl.tbxPatternDescription.Text = string.Empty;
                        }
                        else
                        {
                            mainControl.tbxPatternDescription.Text = selectedPatternInstance.InstanceComments;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                VSService.WriteToOutputWindow(dte, "\nError: " + ex.Message);
            }
        }

        internal void lbxPatternLocation_OnMouseRightButtonUp(object sender, MouseButtonEventArgs eventArgs)
        {
            try
            {
                var selectedItem = VisualUpwardSearch<ListBoxItem>(eventArgs.OriginalSource as DependencyObject) as ListBoxItem;
            }
            catch (Exception ex)
            {
                VSService.WriteToOutputWindow(dte, "\nError: " + ex.Message);
            }
        }

        internal void lbxPatternLocation_OnPreviewMouseRightButtonDown(object sender, MouseButtonEventArgs eventArgs)
        {
            try
            {
                var item = VisualUpwardSearch<ListBoxItem>(eventArgs.OriginalSource as DependencyObject) as ListBoxItem;

                if (item != null)
                {
                    item.IsSelected = true;
                    item.Focus();
                    eventArgs.Handled = true;
                }
            }
            catch (Exception ex)
            {
                VSService.WriteToOutputWindow(dte, "\nError: " + ex.Message);
            }
        }

        //internal void lbxPatternLocation_OnMouseLeftButtonUp(object sender, MouseButtonEventArgs eventArgs)
        //{
        //    // get the selected item
        //    var selectedItem = VisualUpwardSearch<ListBoxItem>(eventArgs.OriginalSource as DependencyObject) as ListBoxItem;
            

        //    // check if selected item is null
        //    if (selectedItem == null)
        //    {
        //        // clear selection on the tree view if necessary
        //        if (mainControl.lbxPatternLocation.SelectedItem != null && mainControl.lbxPatternLocation.SelectedItem is PatternLocationViewModel)
        //        {
        //            (mainControl.lbxPatternLocation.SelectedItem as PatternLocationViewModel).IsSelected = false;
        //        }
                
        //        // display no properties when no item is selected
        //        // mainControl.dgPatternProperties.DataContext = null;
        //    }
        //    else
        //    {
        //        // guarantee the selection of the item
        //        selectedItem.IsSelected = true;

        //        // set the data context to display corresponding properties (either pattern model/instance)
        //        // mainControl.dgPatternProperties.DataContext = (selectedItem.Header as TreeViewItemViewModel).GetProperties();
        //    }
        //}

        internal void RenameMenuItem_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                editableTreeViewItem = mainControl.tvPatternExplorer.SelectedItem as TreeViewItemViewModel;
                if (editableTreeViewItem != null)
                {
                    // save the previous name
                    editableTreeViewItem.PreviousName = (editableTreeViewItem as PatternInstanceViewModel).PatternInstanceName;

                    editableTreeViewItem.IsInEditMode = true;
                    e.Handled = true;
                }
            }
            catch (Exception ex)
            {
                VSService.WriteToOutputWindow(dte, "\nError: " + ex.Message);
            }
        }

        internal void tvPatternExplorer_OnSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
        {
           
        }

        public void tbxEditableText_KeyDown(object sender, KeyEventArgs e)
        {
            try
            {
                if (e.Key == Key.Enter)
                {
                    if ((sender is TextBox) && (((TextBox)sender).Tag is TreeViewItemViewModel))
                    {
                        var item = ((TextBox)sender).Tag as TreeViewItemViewModel;
                        if (item != null)
                        {
                            item.IsInEditMode = false;
                            if (item is PatternInstanceViewModel && (sender is TextBox) &&
                                (item as PatternInstanceViewModel).PatternInstanceName != (sender as TextBox).Text)
                            {
                                var formerName = (item as PatternInstanceViewModel).PatternInstanceName;
                                (item as PatternInstanceViewModel).PatternInstanceName = (sender as TextBox).Text;
                                var successful = item.SaveChanges();
                                if (!successful)
                                {
                                    MessageBox.Show("An instance with the same name already exists! Please enter different name");
                                    (item as PatternInstanceViewModel).PatternInstanceName = formerName;
                                    item.IsInEditMode = true;
                                    return;
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                VSService.WriteToOutputWindow(dte, "\nError: " + ex.Message);
            }
        }

        public void tbxTemplateEditableText_KeyDown(object sender, KeyEventArgs e)
        {
            try
            {
                if (e.Key == Key.Enter)
                {
                    if ((sender is TextBox) && (((TextBox)sender).Tag is TreeViewItemViewModel))
                    {
                        var item = ((TextBox)sender).Tag as TreeViewItemViewModel;
                        if (item != null)
                        {
                            item.IsInEditMode = false;
                            if (item is PatternTemplateViewModel && (sender is TextBox) &&
                                (item as PatternTemplateViewModel).PatternTemplateName != (sender as TextBox).Text)
                            {
                                var formerName = (item as PatternTemplateViewModel).PatternTemplateName;
                                (item as PatternTemplateViewModel).PatternTemplateName = (sender as TextBox).Text;
                                var successful = item.SaveChanges();
                                if (!successful)
                                {
                                    MessageBox.Show("A template with the same name already exists! Please enter different name.");
                                    (item as PatternTemplateViewModel).PatternTemplateName = formerName;
                                    item.IsInEditMode = true;
                                    return;
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                VSService.WriteToOutputWindow(dte, "\nError: " + ex.Message);
            }
        }

        public void EditMenuItem_Click(EnvDTE.DTE dte)
        {
            try
            {
                // get the selected pattern instance
                editableTreeViewItem = mainControl.tvPatternExplorer.SelectedItem as TreeViewItemViewModel;

                if (editableTreeViewItem != null && editableTreeViewItem is PatternInstanceViewModel)
                {
                    // get path to the current SPC file
                    var patternTemplateName = (editableTreeViewItem.Parent as PatternTemplateViewModel).PatternTemplateName;
                    var patternInstanceName = (editableTreeViewItem as PatternInstanceViewModel).PatternInstanceName;
                    var currentSPCFile = IOService.GetPatternInstanceFilePath(patternTemplateName, patternInstanceName, PatternFileType.SPC);

                    // load the configurations from SPC file to memory
                    LoadConfiguration(currentSPCFile);

                    // get path to the template file
                    var patternTemplateFile = IOService.GetPatternInstanceFilePath(patternTemplateName, patternInstanceName, PatternFileType.Template);

                    // open the template for user to edit
                    IOService.OpenFile(dte, patternTemplateFile);
                    dte.ActiveDocument.Activate();

                    // freeze the code editor
                    dte.ActiveDocument.ReadOnly = true;
                }
            }
            catch (Exception ex)
            {
                VSService.WriteToOutputWindow(dte, "\nError: " + ex.Message);
            }
        }

        public void EditTemplateMenuItem_Click(DTE dte)
        {
            try
            {
                // get the selected pattern template
                editableTreeViewItem = mainControl.tvPatternExplorer.SelectedItem as TreeViewItemViewModel;

                if (editableTreeViewItem != null && editableTreeViewItem is PatternTemplateViewModel)
                {
                    var selectedPatternTemplate = editableTreeViewItem as PatternTemplateViewModel;

                    // get path to the template file
                    var patternTemplateFile = IOService.GetPatternTemplateFilePath(selectedPatternTemplate.PatternTemplateName, PatternFileType.Template);

                    // open the template for user to edit
                    IOService.OpenFile(dte, patternTemplateFile);
                    dte.ActiveDocument.Activate();
                }
            }
            catch (Exception ex)
            {
                VSService.WriteToOutputWindow(dte, "\nError: " + ex.Message);
            }
        }

        public void GenerateCodeMenuItem_Click(EnvDTE.DTE dte)
        {
            try
            {
                // get the selected pattern instance
                editableTreeViewItem = mainControl.tvPatternExplorer.SelectedItem as TreeViewItemViewModel;

                if (editableTreeViewItem != null)
                {
                    // get path to the current SPC file
                    var patternTemplateName = (editableTreeViewItem.Parent as PatternTemplateViewModel).PatternTemplateName;
                    var patternInstanceName = (editableTreeViewItem as PatternInstanceViewModel).PatternInstanceName;
                    var currentSPCFile = IOService.GetPatternInstanceFilePath(patternTemplateName, patternInstanceName, PatternFileType.SPC);

                    // get path to the code file
                    var codeFilePath = IOService.GetPatternInstanceFilePath(patternTemplateName, patternInstanceName, PatternFileType.Code);

                    // delete the old code file if there is
                    IOService.DeleteFile(codeFilePath);

                    try
                    {
                        // generate code from the SPC file
                        IOService.GenerateCodeFromTempate(currentSPCFile);

                        // get the list of locations registered with this pattern
                        var locationList = GetLocationList((editableTreeViewItem as PatternInstanceViewModel));

                        // populate the generated code to corresponding registered locations
                        IOService.PopulateCodeToLocations(codeFilePath, locationList);

                        // write result to the output window
                        VSService.WriteToOutputWindow(dte, "Code generated successfully!");
                    }
                    catch (Exception ex)
                    {
                        VSService.WriteToOutputWindow(dte, ex.Message);
                    }
                }
            }
            catch (Exception ex)
            {
                VSService.WriteToOutputWindow(dte, "\nError: " + ex.Message);
            }
        }

        public void ViewCodeMenuItem_Click(DTE dte)
        {
            try
            {
                // get the selected pattern instance
                editableTreeViewItem = mainControl.tvPatternExplorer.SelectedItem as TreeViewItemViewModel;

                if (editableTreeViewItem != null)
                {
                    // get path to the code file
                    var patternTemplateName = (editableTreeViewItem.Parent as PatternTemplateViewModel).PatternTemplateName;
                    var patternInstanceName = (editableTreeViewItem as PatternInstanceViewModel).PatternInstanceName;
                    var codeFilePath = IOService.GetPatternInstanceFilePath(patternTemplateName, patternInstanceName, PatternFileType.Code);

                    // generate code file if it does not exist
                    if (!IOService.FileExists(codeFilePath))
                    {
                        MessageBox.Show("Please generate the code first!");
                        return;
                    }

                    // open the code file to user to see
                    IOService.OpenFile(dte, codeFilePath);
                    dte.ActiveDocument.Activate();

                    // freeze the code editor
                    dte.ActiveDocument.ReadOnly = true;
                }
            }
            catch (Exception ex)
            {
                VSService.WriteToOutputWindow(dte, "\nError: " + ex.Message);
            }
        }

        public void AddNewInstanceMenuItem_Click(DTE dte)
        {
            try
            {
                // make sure that the pattern template is compiled first
                CompileMenuItem_Click(dte, false);

                // get the selected pattern template
                editableTreeViewItem = mainControl.tvPatternExplorer.SelectedItem as TreeViewItemViewModel;

                if (editableTreeViewItem != null)
                {
                    // get the pattern template name
                    var patternTemplateName = (editableTreeViewItem as PatternTemplateViewModel).PatternTemplateName;

                    // determine the dummy name for the new instance
                    var dummyInstanceName = GetDummyInstanceName(editableTreeViewItem as PatternTemplateViewModel);

                    // create new pattern instance with the dummy name
                    var newPatternInstance = new PatternInstance()
                    {
                        Name = dummyInstanceName,
                        Comments = "",
                        PatternTemplate_ID = (editableTreeViewItem as PatternTemplateViewModel).PatternTemplateID
                    };

                    // save the new pattern instance to database
                    dataAccess.AddPatternInstance(newPatternInstance);

                    // create physical files for the new pattern instance
                    CreateFilesForPatternInstance(patternTemplateName, dummyInstanceName);

                    // create new pattern instance view model with the dummy name
                    var newPatternInstanceViewModel = new PatternInstanceViewModel(editableTreeViewItem)
                    {
                        PatternInstanceID = newPatternInstance.ID,
                        PatternInstanceName = dummyInstanceName,
                        InstanceComments = newPatternInstance.Comments,
                        PreviousName = dummyInstanceName
                    };

                    // add the new pattern instance node to the selected pattern template node
                    editableTreeViewItem.Children.Add(newPatternInstanceViewModel);

                    // put the new pattern instance in editable mode
                    newPatternInstanceViewModel.IsInEditMode = true;
                }
            }
            catch (Exception ex)
            {
                VSService.WriteToOutputWindow(dte, "\nError: " + ex.Message);
            }
        }

        public void ReplicateMenuItem_Click(DTE dte)
        {
            try
            {
                // get the selected pattern template
                editableTreeViewItem = mainControl.tvPatternExplorer.SelectedItem as TreeViewItemViewModel;

                if (editableTreeViewItem != null && editableTreeViewItem is PatternInstanceViewModel)
                {
                    var selectedPatternInstanceViewModel = editableTreeViewItem as PatternInstanceViewModel;

                    // get the pattern template name
                    var patternTemplateName = (selectedPatternInstanceViewModel.Parent as PatternTemplateViewModel).PatternTemplateName;

                    // determine the dummy name for the new instance
                    var dummyInstanceName = GetDummyInstanceName(selectedPatternInstanceViewModel.Parent as PatternTemplateViewModel);

                    // make a copy of the pattern instance with the dummy name
                    var newPatternInstance = new PatternInstance()
                    {
                        Name = dummyInstanceName,
                        Comments = selectedPatternInstanceViewModel.InstanceComments,
                        PatternTemplate_ID = (selectedPatternInstanceViewModel.Parent as PatternTemplateViewModel).PatternTemplateID
                    };

                    // save the new pattern instance to database
                    dataAccess.AddPatternInstance(newPatternInstance);

                    // replicate physical files for the new pattern instance
                    ReplicateFilesForPatternInstancce(patternTemplateName, selectedPatternInstanceViewModel.PatternInstanceName, dummyInstanceName);

                    // create new pattern instance view model with the dummy name
                    var newPatternInstanceViewModel = new PatternInstanceViewModel(selectedPatternInstanceViewModel.Parent)
                    {
                        PatternInstanceID = newPatternInstance.ID,
                        PatternInstanceName = dummyInstanceName,
                        InstanceComments = newPatternInstance.Comments,
                        PreviousName = dummyInstanceName
                    };

                    // add the new pattern instance node to the selected pattern template node
                    selectedPatternInstanceViewModel.Parent.Children.Add(newPatternInstanceViewModel);

                    // put the new pattern instance in editable mode
                    newPatternInstanceViewModel.IsInEditMode = true;
                }
            }
            catch (Exception ex)
            {
                VSService.WriteToOutputWindow(dte, "\nError: " + ex.Message);
            }
        }

        public void RemoveInstanceMenuItem_Click(DTE dte)
        {
            try
            {
                // get the selected pattern instance
                editableTreeViewItem = mainControl.tvPatternExplorer.SelectedItem as TreeViewItemViewModel;

                if (editableTreeViewItem != null && editableTreeViewItem is PatternInstanceViewModel)
                {
                    RemovePatternInstance(editableTreeViewItem as PatternInstanceViewModel);
                }
            }
            catch (Exception ex)
            {
                VSService.WriteToOutputWindow(dte, "\nError: " + ex.Message);
            }
        }

        private void RemovePatternInstance(PatternInstanceViewModel patternInstanceViewModel)
        { 
            // get the ID of the selected pattern instance
            var patternInstanceID = patternInstanceViewModel.PatternInstanceID;

            // get the pattern template name and pattern instance name
            var patternTemplateName = (patternInstanceViewModel.Parent as PatternTemplateViewModel).PatternTemplateName;
            var patternInstanceName = patternInstanceViewModel.PatternInstanceName;

            // remove all the instances in the registered locations
            var locationList = GetLocationList(patternInstanceViewModel);
            RemoveInstancesInLocations(patternInstanceName, locationList);

            // remove the selected pattern instance from the database
            dataAccess.RemovePatternInstance(patternInstanceID);

            // remove the physical files for the pattern instance
            RemoveFilesForPatternInstance(patternTemplateName, patternInstanceName);

            // get the parent pattern template view model
            //var patternTemplateViewModel = patternInstanceViewModel.Parent;

            // remove the pattern instance view model from the parent
            //patternTemplateViewModel.Children.Remove(patternInstanceViewModel);   
        }

        public void RemoveTemplateMenuItem_Click(DTE dte)
        {
            try
            {
                // get the selected pattern template
                editableTreeViewItem = mainControl.tvPatternExplorer.SelectedItem as TreeViewItemViewModel;

                if (editableTreeViewItem != null && editableTreeViewItem is PatternTemplateViewModel)
                {
                    var selectedPatternTemplate = editableTreeViewItem as PatternTemplateViewModel;

                    // go through and remove every instance of the selected pattern template
                    if (selectedPatternTemplate.Children != null)
                    {
                        foreach (var child in selectedPatternTemplate.Children)
                        {
                            var patternInstance = child as PatternInstanceViewModel;
                            RemovePatternInstance(patternInstance);
                        }

                        // clear the list of pattern instances
                        selectedPatternTemplate.Children.Clear();
                    }

                    // remove the pattern template from the database
                    dataAccess.RemovePatternTemplate(selectedPatternTemplate.PatternTemplateID);

                    // remove the directory of the pattern template
                    RemoveFilesForPatternTemplate(selectedPatternTemplate.PatternTemplateName);

                    // remove the pattern template view model from the pattern explorer
                    PatternTemplates.Remove(selectedPatternTemplate);
                }
            }
            catch (Exception ex)
            {
                VSService.WriteToOutputWindow(dte, "\nError: " + ex.Message);
            }
        }

        public void NewLocationMenuItem_Click()
        {
            try
            {
                var addNewLocationControl = new AddNewLocationControl(this);
                addNewLocationControl.Popup();
            }
            catch (Exception ex)
            {
                VSService.WriteToOutputWindow(dte, "\nError: " + ex.Message);
            }
        }

        public void UseInCurrentProjectMenuItem_Click(DTE dte)
        {
            try
            {
                // get the current project in the solution explorer
                var currentProject = VSService.GetActiveProject(dte);

                // return if there is no current project
                if (currentProject == null)
                {
                    MessageBox.Show("Please open some projects first!");
                    return;
                }

                // get the physical path to the project
                var projectPath = IOService.GetBaseDirectory(currentProject.FullName);

                // create the folder "PatternLibary" if it is not there yet
                var patternLibDirectoryPath = IOService.GetCombinedPath(projectPath, "PatternLibrary");
                IOService.CreateDirectory(patternLibDirectoryPath);

                // add the physical path to the database if it is not there
                AddLocationToDB(currentProject.Name, patternLibDirectoryPath);

                // get the selected pattern instance
                editableTreeViewItem = mainControl.tvPatternExplorer.SelectedItem as TreeViewItemViewModel;

                // return if there is no selected pattern instance
                if (editableTreeViewItem == null || !(editableTreeViewItem is PatternInstanceViewModel))
                {
                    return;
                }

                // return if the pattern instance has already been added to the project
                if (dataAccess.IsInstanceInLocation((editableTreeViewItem as PatternInstanceViewModel).PatternInstanceID, patternLibDirectoryPath))
                {
                    MessageBox.Show("An instance of this pattern is already in the project!");
                    return;
                }

                // warn user if the code has not been generated yet
                var patternTemplateName = (editableTreeViewItem.Parent as PatternTemplateViewModel).PatternTemplateName;
                var patternInstanceName = (editableTreeViewItem as PatternInstanceViewModel).PatternInstanceName;
                var codeFilePath = IOService.GetPatternInstanceFilePath(patternTemplateName, patternInstanceName, PatternFileType.Code);
                if (!IOService.FileExists(codeFilePath))
                {
                    MessageBox.Show("Please generate the code first!");
                    return;
                }

                // set the relationship between the location and the pattern instance
                dataAccess.AssignInstanceToLocation((editableTreeViewItem as PatternInstanceViewModel).PatternInstanceID, patternLibDirectoryPath);

                // get the destination path of the code file in the project
                var codeFileName = patternInstanceName + ".cs";
                var destCodeFilePath = IOService.GetCombinedPath(patternLibDirectoryPath, codeFileName);

                // copy the code file to the destination
                IOService.CopyFile(codeFilePath, destCodeFilePath);

                // add the directory recursively to the project
                currentProject.ProjectItems.AddFromDirectory(patternLibDirectoryPath);

                // save the current project
                currentProject.Save();
            }
            catch (Exception ex)
            {
                VSService.WriteToOutputWindow(dte, "\nError: " + ex.Message);
            }
        }

        public void RefreshMenuItem_Click(DTE dte)
        {
            try
            {
                // return if there is nothing in the solution explorer
                if ((dte as DTE2).ToolWindows.SolutionExplorer.UIHierarchyItems.Count == 0)
                {
                    MessageBox.Show("Please open some project first!");
                    return;
                }

                // determine the current project
                var currentProject = VSService.GetActiveProject(dte);

                // return if there is no current project
                if (currentProject == null)
                {
                    MessageBox.Show("Please open some projects first!");
                    return;
                }

                // get the physical path to the project
                var projectPath = IOService.GetBaseDirectory(currentProject.FullName);
                var patternLibDirectoryPath = IOService.GetCombinedPath(projectPath, "PatternLibrary");

                // Refresh the pattern explorer to display pattern instances of the specified project
                RefreshPatternExplorer(patternLibDirectoryPath);
            }
            catch (Exception ex)
            {
                VSService.WriteToOutputWindow(dte, "\nError: " + ex.Message);
            }
        }

        public void AddNewTemplateMenuItem_Click(DTE dte)
        {
            try
            {
                // determine the dummy name for the new template
                var dummyTemplateName = GetDummyTemplateName();

                // create new pattern template with the dummy name
                var newPatternTemplate = new PatternTemplate()
                {
                    Name = dummyTemplateName,
                    Comments = ""
                };

                // save the new pattern instance to database
                dataAccess.AddPatternTemplate(newPatternTemplate);

                // create physical files for the new pattern template
                CreateFilesForPatternTemplate(dummyTemplateName);

                // create new pattern template view model with the dummy name
                var newPatternTemplateViewModel = new PatternTemplateViewModel()
                {
                    PatternTemplateID = newPatternTemplate.ID,
                    PatternTemplateName = dummyTemplateName,
                    TemplateComments = newPatternTemplate.Comments,
                    PreviousName = dummyTemplateName
                };

                // add the new pattern template node to the pattern explorer
                PatternTemplates.Add(newPatternTemplateViewModel);

                // put the new pattern instance in editable mode
                newPatternTemplateViewModel.IsInEditMode = true;
            }
            catch (Exception ex)
            {
                VSService.WriteToOutputWindow(dte, "\nError: " + ex.Message);
            }
        }

        /// <summary>
        /// synchronize the x-frame file with the template file with the help of the config file
        /// </summary>
        /// <param name="dte"></param>
        public void PropagateChangesMenuItem_Click(DTE dte)
        {
            try
            {
                // make sure that the pattern template is compiled first
                CompileMenuItem_Click(dte);

                // get the selected pattern template
                editableTreeViewItem = mainControl.tvPatternExplorer.SelectedItem as TreeViewItemViewModel;

                if (editableTreeViewItem != null && editableTreeViewItem is PatternTemplateViewModel)
                {
                    var selectedPatternTemplate = editableTreeViewItem as PatternTemplateViewModel;

                    // get the x-frame file, template file and config file
                    var xframeFilePath = IOService.GetPatternTemplateFilePath(selectedPatternTemplate.PatternTemplateName, PatternFileType.XFrame);
                    var templateFilePath = IOService.GetPatternTemplateFilePath(selectedPatternTemplate.PatternTemplateName, PatternFileType.Template);
                    var configFilePath = IOService.GetPatternTemplateFilePath(selectedPatternTemplate.PatternTemplateName, PatternFileType.SPC);

                    // go through each pattern instance to make changes
                    try
                    {
                        if (selectedPatternTemplate.Children != null)
                        {
                            foreach (var child in selectedPatternTemplate.Children)
                            {
                                var patternInstance = child as PatternInstanceViewModel;
                                patternInstance.UpdateAccordingToTemplate();
                            }
                        }

                        // notify successful propagation
                        VSService.WriteToOutputWindow(dte, "changes have been propagated successfully!");
                    }
                    catch (Exception ex)
                    {
                        VSService.WriteToOutputWindow(dte, "Error: " + ex.Message);
                    }
                }
            }
            catch (Exception ex)
            {
                VSService.WriteToOutputWindow(dte, "\nError: " + ex.Message);
            }
        }

        public void CompileMenuItem_Click(DTE dte)
        {
            try
            {
                // get the selected pattern template
                editableTreeViewItem = mainControl.tvPatternExplorer.SelectedItem as TreeViewItemViewModel;

                if (editableTreeViewItem != null && editableTreeViewItem is PatternTemplateViewModel)
                {
                    var selectedPatternTemplate = editableTreeViewItem as PatternTemplateViewModel;

                    // get the x-frame file, template file and config file
                    var xframeFilePath = IOService.GetPatternTemplateFilePath(selectedPatternTemplate.PatternTemplateName, PatternFileType.XFrame);
                    var templateFilePath = IOService.GetPatternTemplateFilePath(selectedPatternTemplate.PatternTemplateName, PatternFileType.Template);
                    var configFilePath = IOService.GetPatternTemplateFilePath(selectedPatternTemplate.PatternTemplateName, PatternFileType.SPC);

                    try
                    {
                        // load the variables from the template file to memory
                        var variableList = IOService.LoadCodesAndVariablesFromTemplate(templateFilePath);

                        // add variables to config file
                        IOService.CleanUpConfigFile(configFilePath);
                        IOService.AddVariablesToConfigFile(configFilePath, variableList);

                        // get the content of the template file path
                        var templateFileContent = IOService.GetFileContent(templateFilePath);

                        // translate the content to XVCL
                        var xframeFileContent = IOService.GetXFrameFileContent(templateFileContent, variableList);

                        // put the XVCL content to the x-frame file
                        IOService.PutXVCLContent(xframeFilePath, xframeFileContent);

                        // notify successful compilation
                        VSService.WriteToOutputWindow(dte, selectedPatternTemplate.PatternTemplateName + " has been compiled successfully!");
                    }
                    catch (Exception ex)
                    {
                        VSService.WriteToOutputWindow(dte, "Error: " + ex.Message);
                    }
                }
            }
            catch (Exception ex)
            {
                VSService.WriteToOutputWindow(dte, "\nError: " + ex.Message);
            }
        }

        public void CompileMenuItem_Click(DTE dte, bool showOutput)
        {
            try
            {
                // get the selected pattern template
                editableTreeViewItem = mainControl.tvPatternExplorer.SelectedItem as TreeViewItemViewModel;

                if (editableTreeViewItem != null && editableTreeViewItem is PatternTemplateViewModel)
                {
                    var selectedPatternTemplate = editableTreeViewItem as PatternTemplateViewModel;

                    // get the x-frame file, template file and config file
                    var xframeFilePath = IOService.GetPatternTemplateFilePath(selectedPatternTemplate.PatternTemplateName, PatternFileType.XFrame);
                    var templateFilePath = IOService.GetPatternTemplateFilePath(selectedPatternTemplate.PatternTemplateName, PatternFileType.Template);
                    var configFilePath = IOService.GetPatternTemplateFilePath(selectedPatternTemplate.PatternTemplateName, PatternFileType.SPC);

                    try
                    {
                        // load the variables from the template file to memory
                        var variableList = IOService.LoadCodesAndVariablesFromTemplate(templateFilePath);

                        // add variables to config file
                        IOService.CleanUpConfigFile(configFilePath);
                        IOService.AddVariablesToConfigFile(configFilePath, variableList);

                        // get the content of the template file path
                        var templateFileContent = IOService.GetFileContent(templateFilePath);

                        // translate the content to XVCL
                        var xframeFileContent = IOService.GetXFrameFileContent(templateFileContent, variableList);

                        // put the XVCL content to the x-frame file
                        IOService.PutXVCLContent(xframeFilePath, xframeFileContent);

                        if (showOutput)
                        {
                            // notify successful compilation
                            VSService.WriteToOutputWindow(dte, selectedPatternTemplate.PatternTemplateName + " has been compiled successfully!");
                        }
                    }
                    catch (Exception ex)
                    {
                        VSService.WriteToOutputWindow(dte, "Error: " + ex.Message);
                    }
                }
            }
            catch (Exception ex)
            {
                VSService.WriteToOutputWindow(dte, "\nError: " + ex.Message);
            }
        }

        public void ShowAllPatternsMenuItem_Click(DTE dte)
        {
            try
            {
                RefreshPatternTemplates();
            }
            catch (Exception ex)
            {
                VSService.WriteToOutputWindow(dte, "\nError: " + ex.Message);
            }
        }

        public void PropagateInstanceChangesMenuItem_Click(DTE dte)
        {
            try
            {
                // make sure that the pattern instance is compiled first
                GenerateCodeMenuItem_Click(dte);

                // get the selected pattern instance
                editableTreeViewItem = mainControl.tvPatternExplorer.SelectedItem as TreeViewItemViewModel;

                if (editableTreeViewItem != null && editableTreeViewItem is PatternInstanceViewModel)
                {
                    var selectedPatternInstance = editableTreeViewItem as PatternInstanceViewModel;

                    try
                    {
                        // generate and populate code
                        selectedPatternInstance.GenerateAndPopulateCode();

                        // notify successful propagation
                        VSService.WriteToOutputWindow(dte, "changes have been propagated successfully!");
                    }
                    catch (Exception ex)
                    {
                        VSService.WriteToOutputWindow(dte, "Error: " + ex.Message);
                    }
                }
            }
            catch (Exception ex)
            {
                VSService.WriteToOutputWindow(dte, "\nError: " + ex.Message);
            }
        }

        public void AddTemplateDescriptionMenuItem_Click(DTE dte)
        {
            try
            {
                // get the selected pattern template
                editableTreeViewItem = mainControl.tvPatternExplorer.SelectedItem as TreeViewItemViewModel;

                if (editableTreeViewItem != null && editableTreeViewItem is PatternTemplateViewModel)
                {
                    var selectedPatternTemplate = editableTreeViewItem as PatternTemplateViewModel;

                    // get the new description
                    string description = Microsoft.VisualBasic.Interaction.InputBox("Please enter the description for the pattern template", "Edit Description", selectedPatternTemplate.TemplateComments);

                    // update the description of the template
                    selectedPatternTemplate.TemplateComments = description;
                }
            }
            catch (Exception ex)
            {
                VSService.WriteToOutputWindow(dte, "\nError: " + ex.Message);
            }
        }

        public void AddInstanceDescriptionMenuItem_Click(DTE dte)
        {
            try
            {
                // get the selected pattern template
                editableTreeViewItem = mainControl.tvPatternExplorer.SelectedItem as TreeViewItemViewModel;

                if (editableTreeViewItem != null && editableTreeViewItem is PatternInstanceViewModel)
                {
                    var selectedPatternInstance = editableTreeViewItem as PatternInstanceViewModel;

                    // get the new description
                    string description = Microsoft.VisualBasic.Interaction.InputBox("Please enter the description for the pattern template", "Edit Description", selectedPatternInstance.InstanceComments);

                    // update the description of the template
                    selectedPatternInstance.InstanceComments = description;
                }
            }
            catch (Exception ex)
            {
                VSService.WriteToOutputWindow(dte, "\nError: " + ex.Message);
            }
        }

        public void BtnSaveDescription_Click(DTE dte)
        {
            try
            {
                // get the selected node
                editableTreeViewItem = mainControl.tvPatternExplorer.SelectedItem as TreeViewItemViewModel;

                // if the selected node is the pattern template
                if (editableTreeViewItem != null && editableTreeViewItem is PatternTemplateViewModel)
                {
                    var selectedPatternTemplate = editableTreeViewItem as PatternTemplateViewModel;

                    // get the description
                    var description = this.mainControl.tbxPatternDescription.Text;

                    // update the description of the template
                    if (description != selectedPatternTemplate.TemplateComments)
                    {
                        selectedPatternTemplate.TemplateComments = description;
                        dataAccess.UpdateTemplateComment(selectedPatternTemplate.PatternTemplateID, description);
                    }
                }
                else if (editableTreeViewItem != null && editableTreeViewItem is PatternInstanceViewModel)
                {
                    var selectedPatternInstance = editableTreeViewItem as PatternInstanceViewModel;

                    // get the description
                    var description = this.mainControl.tbxPatternDescription.Text;

                    // update the description of the template
                    if (description != selectedPatternInstance.InstanceComments)
                    {
                        selectedPatternInstance.InstanceComments = description;
                        dataAccess.UpdateInstanceComment(selectedPatternInstance.PatternInstanceID, description);
                    }
                }
            }
            catch (Exception ex)
            {
                VSService.WriteToOutputWindow(dte, "\nError: " + ex.Message);
            }
        }

        public void RemoveFromCurrentProjectMenuItem_Click(DTE dte)
        {
            try
            {
                // get the current project in the solution explorer
                var currentProject = VSService.GetActiveProject(dte);

                // return if there is no current project
                if (currentProject == null)
                {
                    MessageBox.Show("Please open some projects first!");
                    return;
                }

                // get the physical path to the project
                var projectPath = IOService.GetBaseDirectory(currentProject.FullName);

                // get the path to the pattern library
                var patternLibDirectoryPath = IOService.GetCombinedPath(projectPath, "PatternLibrary");

                // get the selected pattern instance
                editableTreeViewItem = mainControl.tvPatternExplorer.SelectedItem as TreeViewItemViewModel;

                // return if there is no selected pattern instance
                if (editableTreeViewItem == null || !(editableTreeViewItem is PatternInstanceViewModel))
                {
                    return;
                }

                // remove the instance - location item in the database
                dataAccess.RemoveInstanceFromLocation((editableTreeViewItem as PatternInstanceViewModel).PatternInstanceID, patternLibDirectoryPath);

                // get the pattern instance name
                var patternInstanceName = (editableTreeViewItem as PatternInstanceViewModel).PatternInstanceName;

                // get the destination path of the code file in the project
                var codeFileName = patternInstanceName + ".cs";
                var destCodeFilePath = IOService.GetCombinedPath(patternLibDirectoryPath, codeFileName);

                // ask the user if they want to remove the code file in the project folder
                if (IOService.FileExists(destCodeFilePath))
                {
                    if (MessageBox.Show("Please confirm to delete the code file in the current project", "Confirmation", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
                    {
                        IOService.DeleteFile(destCodeFilePath);
                        currentProject.Save();
                        VSService.WriteToOutputWindow(dte, "Selected pattern instance has been removed from the current project");
                    }
                }
                else
                {
                    MessageBox.Show("No instance of the selected pattern is in the current project.");
                }
            }
            catch (Exception ex)
            {
                VSService.WriteToOutputWindow(dte, ex.Message);
            }
        }

        #endregion

        #region Public Methods

        public void AddNewLocation(string locationName, string locationPath)
        {
            try
            {
                // create new pattern location
                var patternLocation = new PatternLocation()
                {
                    Name = locationName,
                    Path = locationPath
                };

                // add new pattern location to database
                dataAccess.AddPatternLocation(patternLocation);

                // create view model for the new pattern location
                var patternLocationViewModel = new PatternLocationViewModel()
                {
                    LocationID = patternLocation.ID,
                    LocationName = patternLocation.Name,
                    LocationPath = patternLocation.Path
                };

                // add the new pattern location node to the list box
                patternLocations.Add(patternLocationViewModel);
            }
            catch (Exception ex)
            {
                VSService.WriteToOutputWindow(dte, "\nError: " + ex.Message);
            }
        }

        #endregion

        #region Helpers

        private void AddLocationToDB(string projectName, string projectPath)
        {
            dataAccess.AddPatternLocation(projectName, projectPath);
        }

        private void ReplicateFilesForPatternInstancce(string patternTemplateName, string originalPatternInstanceName, string patternInstanceName)
        {
            // create new directory for the new instance
            var directoryPath = IOService.GetFullPath(@"PatternManagementExtension\" + patternTemplateName + @"\" + patternInstanceName);
            IOService.CreateDirectory(directoryPath);

            // copy XFrame file to the new directory
            var originalXFrameFile = IOService.GetPatternInstanceFilePath(patternTemplateName, originalPatternInstanceName, PatternFileType.XFrame);
            var instanceXFrameFile = IOService.GetPatternInstanceFilePath(patternTemplateName, patternInstanceName, PatternFileType.XFrame);
            IOService.CopyFile(originalXFrameFile, instanceXFrameFile);

            // copy template file to the new directory
            var originalTemplateFile = IOService.GetPatternInstanceFilePath(patternTemplateName, originalPatternInstanceName, PatternFileType.Template);
            var instanceTemplateFile = IOService.GetPatternInstanceFilePath(patternTemplateName, patternInstanceName, PatternFileType.Template);
            IOService.CopyFile(originalTemplateFile, instanceTemplateFile);

            // copy config file to the new directory
            var originalConfigFile = IOService.GetPatternInstanceFilePath(patternTemplateName, originalPatternInstanceName, PatternFileType.SPC);
            var instanceConfigFile = IOService.GetPatternInstanceFilePath(patternTemplateName, patternInstanceName, PatternFileType.SPC);
            IOService.CopyFile(originalConfigFile, instanceConfigFile);

            // update the code file name in the config file
            IOService.UpdateCodeFileNameInConfigFile(instanceConfigFile, patternInstanceName);
        }

        private void RemoveFilesForPatternInstance(string patternTemplateName, string patternInstanceName)
        {
            // get the path to the directory of the instance
            var instanceDirectoryPath = IOService.GetFullPath(@"PatternManagementExtension\" + patternTemplateName + @"\" + patternInstanceName);

            // remove the directory
            IOService.DeleteDirectory(instanceDirectoryPath);
        }

        private void CreateFilesForPatternInstance(string patternTemplateName, string patternInstanceName)
        {
            // create new directory for the new instance
            var directoryPath = IOService.GetFullPath(@"PatternManagementExtension\" + patternTemplateName + @"\" + patternInstanceName);
            IOService.CreateDirectory(directoryPath);

            // copy XFrame file to the new directory
            var templateXFrameFile = IOService.GetPatternTemplateFilePath(patternTemplateName, PatternFileType.XFrame);
            var instanceXFrameFile = IOService.GetPatternInstanceFilePath(patternTemplateName, patternInstanceName, PatternFileType.XFrame);
            IOService.CopyFile(templateXFrameFile, instanceXFrameFile);

            // copy template file to the new directory
            var templateTemplateFile = IOService.GetPatternTemplateFilePath(patternTemplateName, PatternFileType.Template);
            var instanceTemplateFile = IOService.GetPatternInstanceFilePath(patternTemplateName, patternInstanceName, PatternFileType.Template);
            IOService.CopyFile(templateTemplateFile, instanceTemplateFile);

            // copy config file to the new directory
            var templateConfigFile = IOService.GetPatternTemplateFilePath(patternTemplateName, PatternFileType.SPC);
            var instanceConfigFile = IOService.GetPatternInstanceFilePath(patternTemplateName, patternInstanceName, PatternFileType.SPC);
            IOService.CopyFile(templateConfigFile, instanceConfigFile);

            // update the code file name in the config file
            IOService.UpdateCodeFileNameInConfigFile(instanceConfigFile, patternInstanceName);
        }

        private void CreateFilesForPatternTemplate(string patternTemplateName)
        {
            // create new directory for the new pattern template
            var templateDirPath = IOService.GetFullPath(@"PatternManagementExtension\" + patternTemplateName);
            IOService.CreateDirectory(templateDirPath);

            // create X-Frame file
            var templateXFrameFile = IOService.GetPatternTemplateFilePath(patternTemplateName, PatternFileType.XFrame);
            var modelTemplateXFrame = IOService.GetFullPath(@"PatternManagementExtension\Template.xvcl");
            IOService.CopyFile(modelTemplateXFrame, templateXFrameFile);

            // set value for the x-frame
            IOService.SetValue(templateXFrameFile, "x-frame", "name", patternTemplateName);

            // create template file
            var templateTemplateFile = IOService.GetPatternTemplateFilePath(patternTemplateName, PatternFileType.Template);
            IOService.CreateFile(templateTemplateFile);

            // create config file
            var templateConfigFile = IOService.GetPatternTemplateFilePath(patternTemplateName, PatternFileType.SPC);
            var modelTemplateConfig = IOService.GetFullPath(@"PatternManagementExtension\Template.config");
            IOService.CopyFile(modelTemplateConfig, templateConfigFile);

            // set value for the config file
            IOService.SetValue(templateConfigFile, "x-frame", "name", patternTemplateName);
            IOService.SetValue(templateConfigFile, "adapt", "x-frame", patternTemplateName + ".xvcl");

            // create a manifest file for the recognition of template
            var recognitionFile = IOService.GetFullPath(@"PatternManagementExtension\" + patternTemplateName + @"\template.manifest"); //IOService.GetPatternTemplateFilePath("template", PatternFileType.Manifest);
            IOService.CreateFile(recognitionFile);
        }

        /// <summary>
        /// get the dummy name for the instance
        /// </summary>
        /// <param name="patternTemplateViewModel"></param>
        /// <returns></returns>
        private string GetDummyInstanceName(PatternTemplateViewModel patternTemplateViewModel)
        {
            // get the pattern template name
            var patternTemplateName = patternTemplateViewModel.PatternTemplateName;

            // go through the names of the pattern instances to determine the dummy name
            string dummyInstanceName = string.Empty;
            int index = 1;
            
            foreach (var childrenViewModel in patternTemplateViewModel.Children)
            {
                var patternInstanceViewModel = childrenViewModel as PatternInstanceViewModel;
                if (patternInstanceViewModel.PatternInstanceName == (patternTemplateName + index))
                {
                    index++;
                }
            }
           
            dummyInstanceName = patternTemplateName + index;

            // return the dummy instance name
            return dummyInstanceName;
        }

        private string GetDummyTemplateName()
        {
            // go through the name of the pattern templates to determine the dummy name
            string dummyTemplateName = string.Empty;
            int index = 1;
            foreach (var patternTemplate in patternTemplates)
            {
                if ((patternTemplate as PatternTemplateViewModel).PatternTemplateName == ("Pattern" + index))
                {
                    index++;
                }
            }
            dummyTemplateName = "Pattern" + index;

            // return the dummy template name
            return dummyTemplateName;
        }

        /// <summary>
        /// Load the configurations from SPC file to memory
        /// </summary>
        /// <param name="currentSPCFile"></param>
        private void LoadConfiguration(string currentSPCFile)
        {
            
        }

        /// <summary>
        /// Renew the view model of pattern template
        /// </summary>
        private void RefreshPatternTemplates()
        {
            PatternTemplates = GetPatternTemplateViewModels(dataAccess.GetAllPatternTemplates());
        }

        private void RefreshPatternTemplates(DTE dte)
        {
            // get the location of the current project
            var currentProject = VSService.GetActiveProject(dte);
            if (currentProject == null)
            {
               PatternTemplates = GetPatternTemplateViewModels(dataAccess.GetAllPatternTemplates());
            }
            else
            {
                // get the physical path to the pattern library of the project
                var projectPath = IOService.GetBaseDirectory(currentProject.FullName);
                var patternLibDirectoryPath = IOService.GetCombinedPath(projectPath, "PatternLibrary"); 

                // display the pattern templates which belong to the project
                PatternTemplates = GetPatternTemplateViewModels(dataAccess.GetAllPatternTemplates(patternLibDirectoryPath), patternLibDirectoryPath);
            }
        }

        private void RefreshPatternExplorer(string patternLibDirectoryPath)
        {
            PatternTemplates = GetPatternTemplateViewModels(dataAccess.GetAllPatternTemplates(patternLibDirectoryPath), patternLibDirectoryPath);
        }

        /// <summary>
        /// Renew the view model of pattern location
        /// </summary>
        private void RefreshPatternLocations()
        {
            patternLocations = GetPatternLocationViewModels(dataAccess.GetAllPatternLocations());
        }

        /// <summary>
        /// Get all the view models of all pattern locations
        /// </summary>
        /// <param name="patternLocations"></param>
        /// <returns></returns>
        private ObservableCollection<PatternLocationViewModel> GetPatternLocationViewModels(IEnumerable<PatternLocation> patternLocations)
        {
            var patternLocationViewModels = new ObservableCollection<PatternLocationViewModel>();

            foreach (var patternLocation in patternLocations)
            {
                var patternLocationViewModel = new PatternLocationViewModel
                {
                    LocationID = patternLocation.ID,
                    LocationName = patternLocation.Name,
                    LocationPath = patternLocation.Path
                };

                patternLocationViewModels.Add(patternLocationViewModel);
            }

            return patternLocationViewModels;
        }

        /// <summary>
        /// Get all the view models of all pattern templates
        /// </summary>
        /// <param name="patternTemplates"></param>
        /// <returns></returns>
        private ObservableCollection<TreeViewItemViewModel> GetPatternTemplateViewModels(IEnumerable<PatternTemplate> patternTemplates)
        {
            var patternTemplateViewModels = new ObservableCollection<TreeViewItemViewModel>();
            
            foreach (var patternTemplate in patternTemplates)
            {
                var patternTemplateViewModel = new PatternTemplateViewModel
                {
                    PatternTemplateID = patternTemplate.ID,
                    PatternTemplateName = patternTemplate.Name,
                    TemplateComments = patternTemplate.Comments,
                    Children = GetPatternInstanceViewModels(patternTemplate.PatternInstances)
                };

                // set parent for each children
                foreach (var children in patternTemplateViewModel.Children)
                {
                    children.Parent = patternTemplateViewModel;
                }

                patternTemplateViewModels.Add(patternTemplateViewModel);
            }

            return patternTemplateViewModels;
        }

        private ObservableCollection<TreeViewItemViewModel> GetPatternTemplateViewModels(IEnumerable<PatternTemplate> patternTemplates, string patternLibDirectoryPath)
        {
            var patternTemplateViewModels = new ObservableCollection<TreeViewItemViewModel>();

            foreach (var patternTemplate in patternTemplates)
            {
                var patternTemplateViewModel = new PatternTemplateViewModel
                {
                    PatternTemplateID = patternTemplate.ID,
                    PatternTemplateName = patternTemplate.Name,
                    TemplateComments = patternTemplate.Comments,
                    Children = GetPatternInstanceViewModels(patternTemplate.PatternInstances, patternLibDirectoryPath)
                };

                // set parent for each children
                foreach (var children in patternTemplateViewModel.Children)
                {
                    children.Parent = patternTemplateViewModel;
                }

                patternTemplateViewModels.Add(patternTemplateViewModel);
            }

            return patternTemplateViewModels;
        }

        private ObservableCollection<TreeViewItemViewModel> GetPatternInstanceViewModels(IEnumerable<PatternInstance> patternInstances, string patternLibDirectoryPath)
        {
            var patternInstanceViewModels = new ObservableCollection<TreeViewItemViewModel>();

            foreach (var patternInstance in patternInstances)
            {
                var displayed = false;
                foreach (var location in patternInstance.PatternLocations)
                {
                    if (location.Path == patternLibDirectoryPath)
                    {
                        displayed = true;
                        break;
                    }
                }
                if (!displayed)
                {
                    continue;
                }

                var patternInstanceViewModel = new PatternInstanceViewModel
                {
                    PatternInstanceID = patternInstance.ID,
                    PatternInstanceName = patternInstance.Name,
                    InstanceComments = patternInstance.Comments
                };
                patternInstanceViewModels.Add(patternInstanceViewModel);
            }

            return patternInstanceViewModels;
        }

        /// <summary>
        /// Get all the view models of all pattern instances
        /// </summary>
        /// <param name="patternInstances"></param>
        /// <returns></returns>
        private ObservableCollection<TreeViewItemViewModel> GetPatternInstanceViewModels(IEnumerable<PatternInstance> patternInstances)
        {
            var patternInstanceViewModels = new ObservableCollection<TreeViewItemViewModel>();

            foreach (var patternInstance in patternInstances)
            {
                var patternInstanceViewModel = new PatternInstanceViewModel
                {
                    PatternInstanceID = patternInstance.ID,
                    PatternInstanceName = patternInstance.Name,
                    InstanceComments = patternInstance.Comments
                };
                patternInstanceViewModels.Add(patternInstanceViewModel);
            }

            return patternInstanceViewModels;
        }

        /// <summary>
        /// Retrieve the parent of a treeview item
        /// </summary>
        /// <param name="dependencyObject"></param>
        /// <returns></returns>
        private TreeViewItem GetParentTreeViewItem(DependencyObject item)
        {
            if (item != null)
            {
                DependencyObject parent = VisualTreeHelper.GetParent(item);
                TreeViewItem parentTreeViewItem = parent as TreeViewItem;
                return parentTreeViewItem ?? GetParentTreeViewItem(parent);
            }
            return null;
        }

        /// <summary>
        /// search for the visual parent object of the specified dependency object
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dependencyObject"></param>
        /// <returns></returns>
        private DependencyObject VisualUpwardSearch<T>(DependencyObject source)
        {
            while (source != null && source.GetType() != typeof(T))
            {
                if (source is Visual || source is Visual3D)
                {
                    source = VisualTreeHelper.GetParent(source);
                }
                else
                {
                    source = LogicalTreeHelper.GetParent(source);
                }
            }
            return source;
        }

        private List<string> GetLocationList(PatternInstanceViewModel patternInstanceViewModel)
        {
            var locationList = new List<string>();

            // get the locations based on ID of the pattern instance
            var locations = dataAccess.GetAllPatternLocations(patternInstanceViewModel.PatternInstanceID);

            foreach (var location in locations)
            {
                locationList.Add(location.Path);
            }

            return locationList;
        }

        private void RemoveInstancesInLocations(string patternInstanceName, List<string> locationList)
        {
            var codeFileName = patternInstanceName + @".cs";
            foreach (var location in locationList)
            {
                var instanceCodeFilePath = IOService.GetCombinedPath(location, codeFileName);
                IOService.DeleteFile(instanceCodeFilePath);
            }
        }

        private void RemoveFilesForPatternTemplate(string patternTemplateName)
        {
            // get the path to the directory of the template
            var templateDirectoryPath = IOService.GetFullPath(@"PatternManagementExtension\" + patternTemplateName);

            // remove the directory
            IOService.DeleteDirectory(templateDirectoryPath);
        }

        #endregion
    }
}
